use std::sync::Arc;

use tauri::Window;
use tokio::{
    io::AsyncWriteExt,
    sync::{Mutex, Semaphore},
};
use tokio_serial::{SerialPortBuilderExt, SerialStream};

use crate::{error::AppErr, utils::get_mut};

use super::{read_handler::read_loop, resp::RecvQueue};

const BAUD_RATE: u32 = 115200;

unsafe impl Sync for ModeSConn {}

pub struct ModeSConn {
    pub port: SerialStream,

    pub recv_mq: RecvQueue,
    pub result_mq: RecvQueue,

    pub seq_lock: Mutex<u8>,
    pub window: Window,
    pub exit_sem: Semaphore,
}

impl ModeSConn {
    pub async fn new(name: &str, window: Window) -> Result<Arc<ModeSConn>, AppErr> {
        let stream = tokio_serial::new(name, BAUD_RATE).open_native_async()?;

        let conn = ModeSConn {
            port: stream,
            window,
            recv_mq: RecvQueue::new(),
            result_mq: RecvQueue::new(),
            seq_lock: Mutex::new(0),
            exit_sem: Semaphore::new(0),
        };

        let conn = Arc::new(conn);
        tokio::spawn(read_loop(conn.clone()));
        Ok(conn)
    }

    pub fn exit(&self) {
        self.exit_sem.add_permits(1);
    }

    pub async fn write_raw(&self, buf: &[u8]) -> Result<(), AppErr> {
        let lock = self.seq_lock.lock().await;

        let port = get_mut(&self.port);

        port.write_all(buf).await?;

        drop(lock);

        // print!("write: ");
        // for v in buf {
        //     print!("{:02x} ", v);
        // }
        // println!();

        Ok(())
    }
}
